package dao

import (
	"dc-news/common/utils"
	"dc-news/dao/cache"
	"dc-news/dao/db"
	"dc-news/dao/model"
	"github.com/go-redis/redis"
	"github.com/spf13/cast"
	"go.uber.org/zap"
)

// GetChannelsByUserId 通过用户id获取已关注的频道
func GetChannelsByUserId(userId int) (channels []string, err error) {
	channels, err = cache.GetUserChannels(userId)
	if err != nil {
		zap.S().Error("通过用户id获取已关注的频道操作缓存错误：", err)
		channels, err = db.GetChannelsByUserId(userId)
		return
	}
	if len(channels) == 0 {
		if cache.GetUserChannelsIsExist(userId) {
			return
		}
		channels, err = db.GetChannelsByUserId(userId)
		if err != nil {
			return
		}
		_ = cache.AddUserChannels(userId, channels)
	}
	return
}

// GetNewsIdListByChannelAndCount 通过频道和数量获取新闻列表
func GetNewsIdListByChannelAndCount(count int, channel string) ([]int, error) {
	ids, err := cache.GetRandomNewsIdByChannelAndCount(channel, count)
	if err != nil {
		zap.S().Error("通过频道和数量获取新闻列表操作数据库错误：", err)
		return nil, err
	}
	if ids == nil {
		idFromDB, err := db.GetAllIdByChannel(channel)
		if err != nil {
			return nil, err
		}
		err = cache.SetAllIdByChannel(channel, idFromDB)
		if err != nil {
			return nil, err
		}
		ids, err = cache.GetRandomNewsIdByChannelAndCount(channel, count)
		if err != nil {
			zap.S().Error("通过频道和数量获取新闻列表操作数据库错误：", err)
			return nil, err
		}
	}
	return ids, nil
}

// GetNewsAbstractById 通过id获取新闻摘要
func GetNewsAbstractById(id int) (abstract *model.NewsAbstract, err error) {
	abstract, err = cache.GetNewsAbstractById(id)
	if err != nil {
		zap.S().Error("通过id获取新闻摘要操作缓存错误：", err)
		err = nil
		abstract, err = db.GetNewsAbstractById(id)
		if err != nil {
			zap.S().Error("通过id获取新闻摘要操作数据库错误：", err)
		}
		return nil, err
	}
	if abstract == nil {
		abstract, err = db.GetNewsAbstractById(id)
		if err != nil {
			zap.S().Error("通过id获取新闻摘要操作数据库错误：", err)
			return nil, err
		}
		zap.S().Debug("get news abstract from db")
		err = cache.SetNewsAbstractById(id, abstract)
		if err != nil {
			zap.S().Error("通过id获取新闻摘要写入缓存错误：", err)
			err = nil
		}
	}
	return abstract, nil
}

// GetNewsById 通过id获取新闻
func GetNewsById(id int) (news *model.News, err error) {
	news, err = cache.GetNewsById(id)
	if err != nil {
		zap.S().Error("通过id获取新闻操作缓存错误：", err)
		err = nil
		news, err = db.GetNewsById(id)
		if err != nil {
			zap.S().Error("通过id获取新闻操作数据库错误：", err)
		}
		return
	}
	if news == nil {
		news, err = db.GetNewsById(id)
		if err != nil {
			zap.S().Error("通过id获取新闻操作数据库错误：", err)
			return
		}
		zap.S().Debug("get news from db")
		err = cache.SetNewsById(id, news)
		if err != nil {
			zap.S().Error("通过id获取新闻写入缓存错误：", err)
			err = nil
		}
	}
	likeCount, _ := GetNewsLikesById(id)
	news.LikeCount = likeCount
	return
}

// GetNewsLikesById 通过id获取新闻点赞数量
func GetNewsLikesById(id int) (like int, err error) {
	like, err = cache.GetNewsLikesById(id)
	if err != nil {
		if err == redis.Nil {
			like = db.GetNewsLikeByID(id)
			err = nil
			err = cache.SetNewsLikesById(id, like)
			if err != nil {
				zap.S().Error("通过id获取点赞数量写入缓存错误：", err)
				err = nil
			}
			zap.S().Debug("get news like from db")
			return
		}
		like = db.GetNewsLikeByID(id)
		return like, nil
	}
	zap.L().Debug("get news like from redis")
	return
}

// AddFavouriteNewsByUserIdAndNewsId 添加收藏
func AddFavouriteNewsByUserIdAndNewsId(userId int, newsId int) (err error) {
	err = db.AddFavouriteNewsByUserIdAndNewsId(userId, newsId)
	if !cache.GetNewsFavouriteExistById(userId) {
		ids, _ := db.GetAllNewsFavouriteByUserId(userId)
		_ = cache.AddNewsFavouriteById(userId, *ids)
		return
	}
	_ = cache.AddNewsFavouriteById(userId, cast.ToIntSlice(newsId))
	return
}

// RemoveFavouriteNewsByUserIdAndNewsId 移除收藏
func RemoveFavouriteNewsByUserIdAndNewsId(userId int, newsId int) (err error) {
	err = db.RemoveFavouriteNewsByUserIdAndNewsId(userId, newsId)
	_ = cache.RemoveNewsFavouriteById(userId, newsId)
	return
}

// AddChannelByUserId 通过用户id添加关注频道
func AddChannelByUserId(id int, channel string) (err error) {
	err = db.AddChannelByUserId(id, channel)
	if err != nil {
		return
	}
	_ = cache.AddUserChannels(id, cast.ToStringSlice(channel))
	return err
}

// RemoveChannelByUserId 通过用户id移除关注频道
func RemoveChannelByUserId(id int, channel string) (err error) {
	err = db.RemoveChannelByUserId(id, channel)
	if err != nil {
		return
	}
	_ = cache.RemoveUserChannels(id, channel)
	return
}

// LikesNewsByUserIdAndNewsId 通过用户id和新闻id点赞新闻
func LikesNewsByUserIdAndNewsId(userId int, newsId int) (err error) {
	err = db.LikesNewsByUserIdAndNewsId(userId, newsId)
	if err != nil {
		return
	}
	if !cache.GetNewsLikeExistById(userId) {
		ids, _ := db.GetAllNewsLikeByUserId(userId)
		_ = cache.AddNewsLikesById(userId, *ids)
		_ = cache.IncrNewsLikesById(newsId)
		return
	}
	_ = cache.IncrNewsLikesById(newsId)
	_ = cache.AddNewsLikesById(userId, cast.ToIntSlice(newsId))
	return
}

// CancelLikesNewsByUserIdAndNewsId 通过用户id和新闻id取消点赞新闻
func CancelLikesNewsByUserIdAndNewsId(userId int, newsId int) (err error) {
	err = db.CancelLikesNewsByUserIdAndNewsId(userId, newsId)
	if !cache.GetNewsLikeExistById(userId) {
		ids, _ := db.GetAllNewsLikeByUserId(userId)
		_ = cache.AddNewsLikesById(userId, *ids)
		_ = cache.IncrNewsLikesById(newsId)
		return
	}
	_ = cache.DecrNewsLikesById(newsId)
	_ = cache.RemoveNewsLikesById(userId, newsId)
	return
}

// GetUserFavouriteNewsById 获取用户收藏新闻列表
func GetUserFavouriteNewsById(id int, p *utils.Pagination) (*[]model.NewsList, error) {
	return db.GetUserFavouriteNewsById(id, p)
}

// GetUserLikesNewsById 获取用户点赞新闻列表
func GetUserLikesNewsById(id int, p *utils.Pagination) (*[]model.NewsList, error) {
	return db.GetUserLikesNewsById(id, p)
}

// GetNewsInfoByUserIdAndNewsId 通过用户id和新闻id获取新闻点赞/收藏信息
func GetNewsInfoByUserIdAndNewsId(userId int, newsId int) (isLikes bool, isFavourite bool, err error) {
	if !(cache.GetNewsLikeExistById(userId) && cache.GetNewsFavouriteExistById(userId)) {
		favourite, _ := db.GetAllNewsFavouriteByUserId(userId)
		_ = cache.AddNewsFavouriteById(userId, *favourite)
		likes, _ := db.GetAllNewsLikeByUserId(userId)
		_ = cache.AddNewsLikesById(userId, *likes)
	}
	isLikes = cache.GetIsLikeNewsById(userId, newsId)
	isFavourite = cache.GetIsFavouriteNewsById(userId, newsId)
	return
}
